package com.devops.admin.job;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.devops.admin.model.DOSExportDataJob;
import com.devops.admin.model.DOSExportDataJobLog;
import com.devops.admin.model.DOSResource;
import com.devops.admin.po.DOSExportDataJobPo;
import com.devops.admin.service.DOSClusterNamespaceService;
import com.devops.admin.service.DOSExportDataJobLogService;
import com.devops.admin.service.DOSExportDataJobService;
import com.devops.admin.service.DOSResourceService;
import com.devops.constant.ExportDataJobLogStatusEnum;
import io.fabric8.kubernetes.api.model.EnvFromSourceBuilder;
import io.fabric8.kubernetes.api.model.batch.v1.JobBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * @author jxt
 * @Notes
 * @date 2024/1/10 9:33
 */
@Slf4j
public class ExportDataJob implements Job {
    @Autowired
    DOSExportDataJobLogService dosExportDataJobLogService;
    @Autowired
    DOSExportDataJobService dosExportDataJobService;
    @Autowired
    DOSResourceService dosResourceService;
    @Autowired
    DOSClusterNamespaceService dosClusterNamespaceService;
    @Value("${export.data.executor.url}")
    private String executorUrl;
    @Value("${export.data.executor.basic-auth.code}")
    private String authCode;
    @Value("${export.data.executor.cluster.id:2}")
    private int clusterId;
    @Value("${export.data.executor.image}")
    private String image;
    @Value("${export.data.executor.command:java}")
    private String command;
    @Value("#{${export.data.executor.args.map:null}}")
    private Map<String, String> argsMap;
    @Value("${export.data.executor.namespace}")
    private String namespace;
    @Value("${export.data.executor.implement.type}")
    private String implementType;
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("export data job started");
        JobDataMap dataMap = jobExecutionContext.getMergedJobDataMap();
        Integer jobId = dataMap.getInt("jobId");

        DOSExportDataJobLog exportDataJobLog = DOSExportDataJobLog.builder()
                .jobId(jobId)
                .triggerAt(LocalDateTime.now())
                .status(ExportDataJobLogStatusEnum.IN_PROGRESS.getCode())
                .build();
        dosExportDataJobLogService.save(exportDataJobLog);

        DOSExportDataJob exportDataJob = dosExportDataJobService.getById(jobId);
        DOSResource dbResource = dosResourceService.getById(exportDataJob.getResourceId());
        DOSExportDataJobPo exportDataJobPo = new DOSExportDataJobPo();
        BeanUtil.copyProperties(exportDataJob, exportDataJobPo);
        exportDataJobPo.setDbName(dbResource.getName());
        exportDataJobPo.setDbType(dbResource.getSubType());
        exportDataJobPo.setLogId(exportDataJobLog.getId());

        if ("n8n".equals(implementType)) {
            httpExecutor(exportDataJobPo, exportDataJobLog);
        }else {
            jobExecutor(exportDataJob, exportDataJobLog);
        }

        log.info("export data job finished");
    }

    private void jobExecutor(DOSExportDataJob exportDataJob, DOSExportDataJobLog exportDataJobLog) {
        try (KubernetesClient client = dosClusterNamespaceService.getClients(clusterId)) {
            String jobName = StrUtil.format("job-{}-{}", exportDataJob.getId(), exportDataJobLog.getId());
            // 创建Job对象
            io.fabric8.kubernetes.api.model.batch.v1.Job job = new JobBuilder()
                    .withApiVersion("batch/v1")
                    .withNewMetadata()
                    .withName(jobName)
                    .endMetadata()
                    .withNewSpec()
                    .withTtlSecondsAfterFinished(10)
                    .withNewTemplate()
                    .withNewSpec()
                    .addNewContainer()
                    .withName("job-container")
                    .withImage(image)
                    .withCommand(command)
                    .withArgs(argsMap.get(exportDataJob.getType().toString()).split(","))
                    .addToArgs(exportDataJob.getId().toString(), exportDataJobLog.getId().toString())
                    .withEnvFrom(new EnvFromSourceBuilder()
                            .withNewConfigMapRef()
                            .withName("export-job-config")
                            .endConfigMapRef()
                            .build())
                    .endContainer()
                    .withRestartPolicy("Never")
                    .endSpec()
                    .endTemplate()
                    .endSpec()
                    .build();

            // 在Kubernetes集群中创建Job
            io.fabric8.kubernetes.api.model.batch.v1.Job createdJob = client.batch().v1().jobs().inNamespace(namespace).resource(job).create();
            log.info("Job created: " + createdJob.getMetadata().getName());

        } catch (Exception e) {
            log.error("创建Job时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void httpExecutor(DOSExportDataJobPo exportDataJobPo, DOSExportDataJobLog exportDataJobLog) throws JobExecutionException {
        //调用执行器接口
        HttpResponse response = HttpRequest.post(executorUrl)
                .header(Header.AUTHORIZATION, "Basic " + authCode)
                .body(JSONUtil.toJsonStr(exportDataJobPo))
                .timeout(5000)
                .execute();
        if (200 != response.getStatus()) {
            exportDataJobLog.setStatus(ExportDataJobLogStatusEnum.FAILED.getCode());
            dosExportDataJobLogService.updateById(exportDataJobLog);
            throw new JobExecutionException("执行器执行失败");
        }
    }
}
